package com.woniu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.entity.CollectAndTest;
import com.woniu.entity.TestDetail;
import com.woniu.entity.TestOutside;
import com.woniu.entity.TestType;
import com.woniu.mapper.*;
import com.woniu.service.CollectAndTestService;
import com.woniu.service.vo.TestPageVo;
import com.woniu.service.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author D
 * @since 2023-03-27 08:24:57
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class CollectAndTestServiceImpl extends ServiceImpl<CollectAndTestMapper, CollectAndTest>
        implements CollectAndTestService {

    @Autowired
    private CollectAndTestMapper collectAndTestMapper;
    @Autowired
    private TestOutsideMapper testOutsideMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TestDetailMapper testDetailMapper;
    @Autowired
    private TestTypeMapper testTypeMapper;
    /**
     * 根据用户编号、收藏类型、当前页和每页数量，从redis或数据库获取收藏页的信息
     *
     * @param userCode     用户编号
     * @param collectType  收藏类型：1为收藏，2为实验
     * @param currentPage  当前页码
     * @param pageSize     每页数量
     * @return             包含收藏页信息的 TestPageVo<TestVo> 对象
     */
    @Override
    public TestPageVo<TestVo> pageCollectByUserCode(Long userCode, Integer collectType,
                                                    Integer currentPage, Integer pageSize) {
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //collectType: 1收藏，2实验
        //redis不为空直接返回
        if (collectType == 1) {
            TestPageVo<TestVo> collectRedis = (TestPageVo<TestVo>) ops.get(userCode + "Collect" + currentPage);
            if (collectRedis != null) return collectRedis;
        } else if (collectType == 2) {
            TestPageVo<TestVo> testRedis = (TestPageVo<TestVo>) ops.get(userCode + "Test" + currentPage);
            if (testRedis != null) return testRedis;
        }

        //redis为空执行
        QueryWrapper<CollectAndTest> collectAndTestQueryWrapper = new QueryWrapper<>();
        collectAndTestQueryWrapper.eq("user_code", userCode)
                .eq("collect_type", collectType)
                .or().eq("collect_type", 3);
        Page<CollectAndTest> page = new Page<>(currentPage, pageSize);
        Page<CollectAndTest> selectPage = collectAndTestMapper.selectPage(page, collectAndTestQueryWrapper);
        List<TestVo> collectAndTestVos = selectPage.getRecords().stream().map(o -> {
            TestDetail testDetail = testDetailMapper.selectById(o.getTestCode());
            TestOutside testOutside = testOutsideMapper.selectById(o.getTestCode());
            TestType testType = testTypeMapper.selectById(testDetail.getTestTypeId());
            return new TestVo().testInfo(testOutside, testType);
        }).collect(Collectors.toList());

        TestPageVo<TestVo> testPageVo = new TestPageVo<>(selectPage.getPages(),selectPage.getCurrent(), selectPage.getSize(),selectPage.getTotal(), collectAndTestVos);
        //存redis
        if (collectType == 1) {
            ops.set(userCode + "Collect" + currentPage, testPageVo, 7, TimeUnit.DAYS);
        } else if (collectType == 2) {
            ops.set(userCode + "Test" + currentPage, testPageVo, 7, TimeUnit.DAYS);
        }
        return testPageVo;
    }
    /**
     * 根据用户名、当前页和每页数量，从数据库获取收藏的靶场信息
     * @param userCode     用户userCode
     * @param currentPage  当前页码
     * @param size         每页数量
     * @return             包含靶场信息的 TestPageVo<TestVo> 对象
     */
    @Override
        public TestPageVo<TestVo> getCollect(Long userCode, Long currentPage, Long size) {

        //先查询收藏表中的收testCode
        QueryWrapper<CollectAndTest> collectAndTestQueryWrapper = new QueryWrapper<>();
        collectAndTestQueryWrapper.eq("user_code", userCode);
        collectAndTestQueryWrapper.in("collect_type", 1, 3);
        //没有收藏返回null
        List<CollectAndTest> collectAndTests = collectAndTestMapper.selectList(collectAndTestQueryWrapper);
        if (collectAndTests == null || collectAndTests.size() == 0) {
            return null;
        }

        Set<Long> testCodes = collectAndTests.stream().map(collectAndTest -> {
            return collectAndTest.getTestCode();
        }).collect(Collectors.toSet());
        //分页查询testDetail
        Page<TestDetail> page = new Page<>(currentPage,size);
        QueryWrapper<TestDetail> testDetailQueryWrapper = new QueryWrapper<>();
        testDetailQueryWrapper.in("test_code", testCodes);
        testDetailQueryWrapper.orderByDesc("test_code");
        Page<TestDetail> testDetails = testDetailMapper.selectPage(page,testDetailQueryWrapper);
        //查询testOutside
        QueryWrapper<TestOutside> testOutsideQueryWrapper = new QueryWrapper<>();
        testOutsideQueryWrapper.in("test_code", testCodes);
        testOutsideQueryWrapper.orderByDesc("test_code");
        List<TestOutside> testOutsides = testOutsideMapper.selectList(testOutsideQueryWrapper);
        //根据相同testCode存入testVo
        List<TestVo> testVos = testOutsides.stream().map(testOutside -> {
            TestVo testVo = new TestVo();
            testDetails.getRecords().stream().forEach(testDetail -> {
                if (testDetail.getTestCode().equals(testOutside.getTestCode())) {
                    testVo.testOutsideToTestVo(testOutside, testVo);
                    testVo.testDetailToTestVo(testDetail, testVo);
                }
            });
            collectAndTests.stream().forEach(collectAndTest -> {
                if (testVo.getTestCode().equals(collectAndTest.getTestCode().toString())){
                    testVo.setCollectTime(collectAndTest.getCollectionTime());
                }
            });
            return testVo;
        }).sorted(Comparator.comparing(TestVo::getCollectTime).reversed()).collect(Collectors.toList());
        TestPageVo<TestVo> testPageVo = new TestPageVo<>();
        testPageVo.setPageVo(testVos);
        testPageVo.setPages(testDetails.getPages());
        testPageVo.setSize(testDetails.getSize());
        testPageVo.setTotal(testDetails.getTotal());
        testPageVo.setCurrentPage(testDetails.getCurrent());

        return testPageVo;
    }

    /**
     * 收藏靶场，将靶场与用户绑定
     *
     * @param testCode 靶场编码
     * @param userCode 用户编码
     * @return 是否收藏成功
     */
    @Override
    public Boolean collect(Long testCode, Long userCode) {
        //先查询是否已经收藏
        QueryWrapper<CollectAndTest> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("test_code", testCode);
        queryWrapper.eq("user_code", userCode);
        CollectAndTest collectAndTests = collectAndTestMapper.selectOne(queryWrapper);
        if (collectAndTests == null) {
            //没有收藏，插入收藏记录
            CollectAndTest collectAndTest = new CollectAndTest();
            collectAndTest.setTestCode(testCode);
            collectAndTest.setUserCode(userCode);
            collectAndTest.setScore(0);
            collectAndTest.setCollectionTime(new Date());
            collectAndTest.setCollectType(1);
            collectAndTestMapper.insert(collectAndTest);
            return true;
        } else {
            //已经收藏，修改收藏记录
            if (collectAndTests.getCollectType() == 2) {
                collectAndTests.setCollectType(3);
                collectAndTests.setCollectionTime(new Date());
                collectAndTestMapper.updateById(collectAndTests);
                return true;
            } else if (collectAndTests.getCollectType() == 1) {
                collectAndTestMapper.deleteById(collectAndTests.getId());
                return true;
            }else if (collectAndTests.getCollectType() == 3) {
                collectAndTests.setCollectType(2);
                collectAndTests.setTestTime(new Date());
                collectAndTests.setCollectionTime(new Date());
                collectAndTestMapper.updateById(collectAndTests);
                return true;
            }
        }
        return false;
    }
    /**
     * 查询指定用户对指定靶场的收藏记录
     *
     * @param userCode 用户code
     * @param testCode 靶场code
     * @return 指定用户对指定靶场的收藏记录
     */
    @Override
    public CollectAndTest getUserOneCollect(Long userCode, Long testCode) {
        QueryWrapper<CollectAndTest> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("test_code", testCode);
        queryWrapper.eq("user_code", userCode);
        return collectAndTestMapper.selectOne(queryWrapper);
    }
}
